package org.jsbd.boss.action;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import edu.hziee.cap.common.util.Md5Utils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.jsbd.boss.bto.HttpResult;
import org.jsbd.boss.common.ConstantsCmp;
import org.jsbd.boss.common.ResponseUtils;
import org.jsbd.boss.common.redis.RedisClient;
import org.jsbd.boss.domian.SdkFileBean;
import org.jsbd.boss.domian.channel.SoUploadLog;
import org.jsbd.boss.mq.MqLogManager;
import org.jsbd.boss.mq.UserLogManager;
import org.jsbd.boss.service.IFileUploadService;
import org.jsbd.boss.service.ITaskPoolService;
import org.jsbd.boss.service.impl.CacheParamManager;
import org.jsbd.boss.service.impl.ExOnlineLoginTriggerService;
import org.jsbd.boss.service.impl.TaskUtil;
import org.jsbd.boss.task.FileUploadTask;
import org.jsbd.boss.util.AesUtils;
import org.jsbd.boss.util.CacheKey;
import org.jsbd.boss.util.DateUtil;
import org.jsbd.boss.util.PropertiesUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URLDecoder;
import java.util.Date;
import java.util.concurrent.atomic.AtomicInteger;
import java.util.zip.GZIPInputStream;

@Controller
@RequestMapping("/qy")
public class OnlineLoginTriggerController {

    private static final Logger logger = LoggerFactory.getLogger(OnlineLoginTriggerController.class);

    @Autowired
    private ExOnlineLoginTriggerService exOnlineLoginTriggerService;
    @Autowired
    private IFileUploadService fileUploadService;

    @Resource
    private ITaskPoolService taskPoolService;

    private static final String SO_KEY = PropertiesUtil.getValue("so.aes.key", "b4c656e98e6bd0d7");
    private static final String SO_VIS = PropertiesUtil.getValue("so.aes.vis", "d4e03524d09d544a");

    @Autowired
    private RedisClient<String, Object> redisClient;
    @Autowired
    private CacheParamManager cacheParamManager;
    
    private static AtomicInteger concurrency=new AtomicInteger();

    @ResponseBody
    @RequestMapping(value = "/getOnlineLoginHttpReq", method = RequestMethod.POST)
    public void getOnlineLoginHttpReq(HttpServletRequest request, HttpServletResponse resp) {

        logger.debug("getOnlineLoginHttpReq is start");
        String result = getRequestFromGzip(request);

        logger.info("getOnlineLoginHttpReq result [{}]", result);
        // 如果为空就直接返回
        if (StringUtils.isBlank(result)) {
            ResponseUtils.renderJsonGzip(resp, "{resultCode:0}");
            return;
        }

        HttpResult httpResult = null;
        try {
            JSONObject jsonObject = JSONObject.parseObject(result);
            httpResult = TaskUtil.initHttpResult(jsonObject);
        } catch (Exception e) {
            logger.error("json解析出错", e);
            ResponseUtils.renderJsonGzip(resp, "{resultCode:0}");
            return;
        }
        String visitIP = getIpAddr(request);
        httpResult.setVisitIp(visitIP);
        String response = exOnlineLoginTriggerService.getOnlineLoginHttpReq(httpResult);
        ResponseUtils.renderJsonGzip(resp, response);

    }


    @ResponseBody
    @RequestMapping(value = "/acceptSdkFileReq", method = RequestMethod.POST)
    public void acceptSdkFileReq(HttpServletRequest request, HttpServletResponse resp) throws Exception {
        String result = "{resultCode:1}";
        String data = getParamFromGzip(request);
        if (StringUtils.isBlank(data)) {
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }

        logger.info("acceptSdkFileReq is [{}]", data);

        SdkFileBean sdkFile = JSON.parseObject(data, SdkFileBean.class);
        String file = sdkFile.getFile();
        final String filename = sdkFile.getFilename();
        String uuid = sdkFile.getUuid();
        final String md5 = sdkFile.getMd5();

        if (StringUtils.isBlank(uuid) || StringUtils.isBlank(md5) || StringUtils.isBlank(file) || StringUtils.isBlank(filename)) {
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }

        final byte[] fileData = Base64.decodeBase64(file);
        final String objectName = "sdkFile/" + uuid + "/" + filename;
        taskPoolService.exec(new FileUploadTask(fileData, ConstantsCmp.BUCKET_NAME, objectName, filename, md5));
        ResponseUtils.renderJson(resp, result);
    }
    
    @ResponseBody
    @RequestMapping(value = "/acceptFileListReq", method = RequestMethod.POST)
    public void acceptFileListReq(HttpServletRequest request, HttpServletResponse resp) throws Exception {
    	String maxCount=(String)cacheParamManager.getParamValue("ACCEPT_MAX_NUM");
    	if(StringUtils.isBlank(maxCount)) {
    		maxCount="100";
    	}
    	
    	int count=concurrency.getAndIncrement();
    	if(count>Integer.valueOf(maxCount)) {
    		logger.warn("当前下载文件数量过多,防止内存溢出，丢弃");
    		ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
    	}
    	
    	try {
    		String result = "{resultCode:1}";
            String data = getParamFromGzip(request);
            if (StringUtils.isBlank(data)) {
                ResponseUtils.renderJson(resp, "{resultCode:0}");
                return;
            }

            logger.info("data is [{}]",data);
            
            JSONObject json=JSON.parseObject(data);
            String uuid=json.getString("uuid");
            JSONArray files=json.getJSONArray("files");
            if (StringUtils.isBlank(uuid)||files==null||files.isEmpty()) {
                ResponseUtils.renderJson(resp, "{resultCode:0}");
                return;
            }
            
            StringBuffer buffer=new StringBuffer();
            
            for(int i=0;i<files.size();i++) {
            	JSONObject fileInfo=files.getJSONObject(i);
            	String filename=fileInfo.getString("filename");
            	String filedata=fileInfo.getString("file");
            	String md5=fileInfo.getString("md5");
            	
            	if(StringUtils.isBlank(filename)||StringUtils.isBlank(filedata)||StringUtils.isBlank(md5)) {
            		continue;
            	}
            	buffer.append(filename+",");
            	
            	final byte[] fileData = Base64.decodeBase64(filedata);
                final String objectName = "sdkFile/" + uuid + "/" + filename;
                taskPoolService.exec(new FileUploadTask(fileData, ConstantsCmp.BUCKET_NAME, objectName, filename, md5));
            }
            UserLogManager.addSdkFileSuccLog(uuid);
            logger.warn("sdkFile upload succ and uuid is [{}],file[{}]",buffer.toString());
            ResponseUtils.renderJson(resp, result);
    	}catch(Exception e){
    		logger.error("acceptFileListReq error",e);
    	}finally {
    		concurrency.decrementAndGet();
    	}
    }
    

    /**
     * 文件传输完成通知接口
     *
     * @param request
     * @param resp
     * @throws Exception
     * @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>
     */
    @ResponseBody
    @RequestMapping(value = "/uploadFinish", method = RequestMethod.POST)
    public void uploadFileFinish(HttpServletRequest request, HttpServletResponse resp) throws Exception {
        String result = "{resultCode:1}";
        String data = getParamFromGzip(request);
        if (StringUtils.isBlank(data)) {
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }

        logger.warn("uploadFinish data is [{}]", data);
        JSONObject json = JSON.parseObject(data);
        String uuid = json.getString("uuid");
        redisClient.put(CacheKey.FILE_UPLOAD_FINISH_KEY + uuid, "1", 60 * 60 * 24);
        ResponseUtils.renderJson(resp, result);
    }

    /**
     * so文件传输
     *
     * @param request
     * @param resp
     * @throws Exception
     * @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>
     */
    @ResponseBody
    @RequestMapping(value = "/soInfoUpload", method = RequestMethod.POST)
    public void soInfoUpload(HttpServletRequest request, HttpServletResponse resp) throws Exception {
        String result = "{resultCode:1}";
        String data = getParamFromGzip(request);
        if (StringUtils.isBlank(data)) {
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }

        JSONObject json = JSON.parseObject(data);
        String uuid = json.getString("uuid");
        String dataMd5 = json.getString("md5");
        String soStr = json.getString("data");
        if (!Md5Utils.getMd5(soStr).equals(dataMd5)) {
            logger.error("数据传输不完整[{}]", data);
            addLog(json,0,"数据传输不完整");
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }
        
        logger.info("soInfoUpload soStr=[{}],SO_KEY={},SO_VIS={}", new Object[]{soStr, SO_KEY, SO_VIS});
        String soValue = AesUtils.decrypt(soStr, SO_KEY, SO_VIS);
        if (StringUtils.isBlank(soValue)) {
            addLog(json,0,"解密失败");
            logger.error("soInfoUpload 解密失败 data is [{}],uuid[{}]", data,uuid);
            ResponseUtils.renderJson(resp, "{resultCode:0}");
            return;
        }

        final String md5 = Md5Utils.getMd5(soValue);
        logger.warn("soInfoUpload 解密成功 data is [{}],uuid[{}]", soValue,uuid);
        addLog(json,1,"解密成功");
        UserLogManager.addSoFileSuccLog(uuid);
        
        redisClient.put(CacheKey.FILE_UPLOAD_FINISH_KEY + uuid, "1", 60 * 60 * 24);
        
        final byte[] fileData = soValue.getBytes("UTF-8");
        final String fileName = "newSo";
        final String objectName = "sdkFile/" + uuid + "/" + fileName;
        taskPoolService.exec(new FileUploadTask(fileData, ConstantsCmp.BUCKET_NAME, objectName, fileName, md5));
        ResponseUtils.renderJson(resp, result);
    }
    
    private void addLog(JSONObject json,int status,String msg) {
    	SoUploadLog log=new SoUploadLog();
    	log.setUuid(json.getString("uuid"));
    	log.setHsman(json.getString("hsman"));
    	log.setHstype(json.getString("hstype"));
    	log.setStatus(status);
    	log.setRemark(msg);
    	log.setCreateTime(DateUtil.getCurrentDateYmdHmsStr(new Date()));
    	MqLogManager.saveSoUploadLog(log);
    }

    /**
     * Gzip解压
     *
     * @param request
     * @return
     * @author <a href="mailto:zhouchao@zhexinit.com" >周超</a>
     */
    private String getParamFromGzip(HttpServletRequest request) {
        try {
            GZIPInputStream gzin = new GZIPInputStream(request.getInputStream());
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            byte[] buffer = new byte[1024];

            int len;
            while ((len = gzin.read(buffer)) != -1) {
                out.write(buffer, 0, len);
            }
            out.close();
            gzin.close();

            return out.toString("UTF-8");
        } catch (IOException e) {
            logger.error("Gzip解析失败：", e);
        }
        return null;
    }

    private String getRequestFromGzip(HttpServletRequest request) {
        try {
            GZIPInputStream gzin = new GZIPInputStream(request.getInputStream());
            InputStreamReader isr = new InputStreamReader(gzin);
            java.io.BufferedReader br = new java.io.BufferedReader(isr);
            StringBuffer sb = new StringBuffer();
            String tempbf;
            while ((tempbf = br.readLine()) != null) {
                sb.append(tempbf);
            }
            br.close();
            isr.close();
            gzin.close();

            return URLDecoder.decode(sb.toString().substring("result=".length()), "UTF-8");
        } catch (IOException e) {
            logger.error("Gzip解析失败：", e);
        }
        return "";
    }

    /**
     * 得到请求的真实IP
     *
     * @param request
     * @return
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("Client_IP");
        if (ip == null || ip.isEmpty()) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}
